//[task.c]
/*
 * 程序清单：这是一个 串口 设备使用例程
 * 例程导出了 uart_sample 命令到控制终端
 * 命令调用格式：uart_sample uart1
 * 命令解释：命令第二个参数是要使用的串口设备名称，为空则使用默认的串口设备
 * 程序功能：通过串口输出字符串"hello RT-Thread!"，然后错位输出输入的字符
 */
#include <rtthread.h>
#include <rtdevice.h>
#include  <string.h> //add by chow
#include "board.h"
#include "drv_soft_spi.h"
//
#include <stdint.h>
#include <rtdevice.h>
#include "spi_flash.h"
#include "spi_flash_sfud.h"
#include <dfs_elm.h>
#include <dfs_fs.h>
#include <dfs_posix.h>
#include "drv_gpio.h"

#include "serprog.h"

#define SAMPLE_UART_NAME "uart1"
/* 用于接收消息的信号量 */
static struct rt_semaphore rx_sem;
static rt_device_t serial;

#if 1

void usb_putc(char ch)
{
    rt_device_write(serial, 0, &ch, 1);
}

char usb_getc(void)
{
    char ch = 0;
    rt_err_t err;

    while (rt_device_read(serial, -1, &ch, 1) != 1)
    {
        /* 阻塞等待接收信号量，等到信号量后再次读取数据 */
        //rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
        err = rt_sem_take(&rx_sem, (30000 / 1)); //5秒超时
        if (err == -RT_ETIMEOUT)
        {
            rt_kprintf("rt_sem_take(&rx_sem, (30000/RT_TICK_PER_SECOND/1000)) RT_ETIMEOUT \n");
        }
        else
        {
            //rt_kprintf("uart1 recve 1 byte \n");
        }
    }
    return ch;
}

#define dbg  rt_kprintf
#define SEND usb_putc
#define RECEIVE usb_getc
#define uint32_t rt_int32_t
#define uint8_t rt_int8_t

uint32_t usb_getu24(void)
{
    uint32_t val = 0;

    val = (uint32_t) usb_getc() << 0;
    val |= (uint32_t) usb_getc() << 8;
    val |= (uint32_t) usb_getc() << 16;

    return val;
}

uint32_t usb_getu32(void)
{
    uint32_t val = 0;

    val = (uint32_t) usb_getc() << 0;
    val |= (uint32_t) usb_getc() << 8;
    val |= (uint32_t) usb_getc() << 16;
    val |= (uint32_t) usb_getc() << 24;

    return val;
}

void usb_putu32(uint32_t ww)
{
    usb_putc(ww >> 0 & 0x000000ff);
    usb_putc(ww >> 8 & 0x000000ff);
    usb_putc(ww >> 16 & 0x000000ff);
    usb_putc(ww >> 24 & 0x000000ff);
}

void spi_putc(uint8_t c)
{
    printf("%2x ", c & 0xff);

}

#if 1
#define W25Q_SPI_DEVICE_NAME "25Q256" //设备名字不能重名,要短
static struct rt_spi_device *spi_dev_w25q;
rt_uint8_t w25x_device_id1[4] = { 0x90, 0x00, 0x00, 0x00 };
rt_uint8_t id1[5] = { 0 };

//测试读取ID 的各种方式OK
void spi_test()
{
    rt_uint8_t w25x_read_id = 0x90;
    rt_uint8_t write_buf[100] = { 0 }; //{0x5a,0x5a,0x5a,0x5a,0x5a};
    memset(write_buf, 0xa5, 100);
    rt_uint8_t read_buf[100] = { 0 };
//
    rt_base_t pin_cs = rt_pin_get("PA.5");
    rt_soft_spi_device_attach("spi0", W25Q_SPI_DEVICE_NAME, RT_NULL, pin_cs);
    rt_kprintf("rt_soft_spi_device_attach End\n");
//
//查找 spi 设备获取地址
    spi_dev_w25q = (struct rt_spi_device *) rt_device_find(W25Q_SPI_DEVICE_NAME);
    if (!spi_dev_w25q)
    {
        rt_kprintf("spi sample run failed\n");
    }
    else
    {
        struct rt_spi_configuration cfg;
        cfg.data_width = 8;
        cfg.mode = RT_SPI_MASTER | RT_SPI_MSB | RT_SPI_MODE_0;
        cfg.max_hz = 1 * 1000; //1.92 M
        rt_spi_configure(spi_dev_w25q, &cfg);
        struct rt_spi_message msg1, msg2;
        w25x_device_id1[0] = 0x90;
        w25x_device_id1[1] = 0x00;
        w25x_device_id1[2] = 0x00;
        w25x_device_id1[3] = 0x00;
        msg1.send_buf = w25x_device_id1;
        msg1.recv_buf = RT_NULL;
        msg1.length = 4;
        msg1.cs_take = 1;
        msg1.cs_release = 0;
        msg1.next = &msg2;
        msg2.send_buf = RT_NULL;
        msg2.recv_buf = id1;
        msg2.length = 5;
        msg2.cs_take = 0;
        msg2.cs_release = 1;
        msg2.next = RT_NULL;
        rt_spi_transfer_message(spi_dev_w25q, &msg1);
        rt_kprintf("use rt_spi_transfer_message() read w25q ID is:%02x %02x %02x %02x %02x\n", id1[0], id1[1], id1[2],
                id1[3], id1[4]);

        //////////////////
        ///
        memset(id1, 0, 5);
        ///
        w25x_device_id1[0] = 0x9F;
        w25x_device_id1[1] = 0x00;
        w25x_device_id1[2] = 0x00;
        w25x_device_id1[3] = 0x00;
        msg1.send_buf = w25x_device_id1;
        msg1.recv_buf = RT_NULL;
        msg1.length = 1;
        msg1.cs_take = 1;
        msg1.cs_release = 0;
        msg1.next = &msg2;
        msg2.send_buf = RT_NULL;
        msg2.recv_buf = id1;
        msg2.length = 3;
        msg2.cs_take = 0;
        msg2.cs_release = 1;
        msg2.next = RT_NULL;
        rt_spi_transfer_message(spi_dev_w25q, &msg1);
        rt_kprintf("use rt_spi_transfer_message() read w25q ID is:%02x %02x %02x %02x %02x\n", id1[0], id1[1], id1[2],
                id1[3], id1[4]);
        //////////
        ///  直接SPI操作读写
        /* 方式1：使用 rt_spi_send_then_recv()发送命令读取ID */
        memset(id1, 0, sizeof(id1));

        rt_spi_send_then_recv(spi_dev_w25q, &w25x_read_id, 1, id1, 5);
        rt_kprintf("use rt_spi_send_then_recv() read w25q ID is:%x%x\n", id1[3], id1[4]);
        ///

    }
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(spi_test, spi_test sample);
#endif

void spi_bulk_write(uint32_t size)
{
    printf("spi_bulk_write size=%d\r\n", size);

    /* Prepare alignment */
    //  if (size >= (USB_Rx_len - USB_Rx_ptr_out))
    {
        //  size -= (USB_Rx_len - USB_Rx_ptr_out);
        // while (USB_Rx_ptr_out != USB_Rx_len)
        //  spi_putc(usb_getc());
    }
    /* else: size << VCP_DATA_SIZE, no bulk transfer */

    /* Do bulk transfer */
    while (size != 0)
    {
        //   usb_getp();

        //   if (USB_Rx_len < VCP_DATA_SIZE)
        {
            /* Host is not feeding fast enough / finish the left-over bytes */
            //   size -= USB_Rx_len;
            // while (USB_Rx_ptr_out != USB_Rx_len)
            spi_putc(usb_getc());
            size--;
        }
        // else
        {
            //  size -= VCP_DATA_SIZE;
            /* DMA Engine must be configured for EVERY transfer */
            // dma_conf_spiwrite();
            //  dma_commit();
        }
    }
    printf("spi_bulk_write  end\r\n");

}

void spi_bulk_read(uint32_t size)
{
    /* Flush buffer and make room for DMA */
    static int i;
    printf("spi_bulk_read size=%d\r\n", size);
    // if (USB_Tx_ptr_in != 0)
    //  usb_putp();

    /* Do bulk transfer */
    // while (size >= VCP_DATA_SIZE)
    {
        /* DMA Engine must be configured for EVERY transfer */
        //  dma_conf_spiread();
        //  dma_commit();
//
        //USB_Tx_ptr_in = VCP_DATA_SIZE;
        //usb_putp();
        //   size -= VCP_DATA_SIZE;
    }

    /* Finish the left-over bytes */
    if (size != 0)
    {
        for (i = 0; i < size; i++)
        {
            // SPI_I2S_SendData(SPI_BUS_USED, 0);
            // while (SPI_I2S_GetFlagStatus(SPI_BUS_USED, SPI_I2S_FLAG_RXNE) == RESET)
            //   ;
            // USB_Tx_Buf[i] = SPI_I2S_ReceiveData(SPI_BUS_USED);
            // printf("%2x ", USB_Tx_Buf[i]);
        }
        //USB_Tx_ptr_in = size;
    }
    printf("spi_bulk_read end\r\n");

}

#define SPI_DEVICE_NAME_SERPROG "spi_ser" //设备名字不能重名,要短

void spi_tran(uint32_t slen, uint32_t rlen)
{
    uint8_t recv_buf[1];
    uint8_t send_buf[1];
    uint32_t i = 0;

    rt_kprintf("spi_tran start slen=%08d,rlen=%08d \r\n", slen, rlen);
    //
    //防止重复操作
    spi_dev_w25q = (struct rt_spi_device *) rt_device_find(SPI_DEVICE_NAME_SERPROG);
    if (!spi_dev_w25q)
    {
        rt_kprintf("SPI flash not found  %s ,attach start\n", SPI_DEVICE_NAME_SERPROG);
        rt_base_t pin_cs = rt_pin_get("PA.5");
        rt_soft_spi_device_attach("spi0", SPI_DEVICE_NAME_SERPROG, RT_NULL, pin_cs);
        rt_kprintf("rt_soft_spi_device_attach  %s\n", SPI_DEVICE_NAME_SERPROG);
    }
//
//查找 spi 设备获取地址
    spi_dev_w25q = (struct rt_spi_device *) rt_device_find(SPI_DEVICE_NAME_SERPROG);

    if (!spi_dev_w25q)
    {
        rt_kprintf("SPI_DEVICE_NAME_SERPROG  %s not Found\n", SPI_DEVICE_NAME_SERPROG);
    }
    else
    {

        struct rt_spi_configuration cfg;
        cfg.data_width = 8;
        cfg.mode = RT_SPI_MASTER | RT_SPI_MSB | RT_SPI_MODE_0;
        cfg.max_hz = 1 * 1000; //1.92 M
        rt_spi_configure(spi_dev_w25q, &cfg);
        struct rt_spi_message msg1, msg2;

        //接收串口要发送到SPI的数据
        // memset(recv_buf,0,sizeof(recv_buf));
        //memset(recv_buf,0,sizeof(recv_buf));
        msg1.send_buf = send_buf;
        msg1.recv_buf = RT_NULL;
        msg1.length = 1;
        msg1.cs_take = 1;
        msg1.cs_release = 0;
        msg1.next = RT_NULL;
        dbg("spi write: ");
        for (i = 0; i < slen; i++)
        {
            send_buf[0] = 0xff & usb_getc();
            if (slen < 10)
            {
                dbg("%2X ", send_buf[0] & 0xff);
            }
            rt_spi_transfer_message(spi_dev_w25q, &msg1);
        }
        dbg("\r\n");
        ///////////////////////////////////////
        ///
        usb_putc(S_ACK);        //
        //
        /////////////////////////////////////////
        ///
        //接收处理
        msg1.send_buf = RT_NULL;
        msg1.recv_buf = recv_buf;
        msg1.length = 1;
        msg1.cs_take = 1;
        msg1.cs_release = 0;
        msg1.next = RT_NULL;
        dbg("spi read: ");
        for (i = 0; i < rlen; i++)
        {
            if ((i + 1) == rlen)
            {
                msg1.cs_release = 1;        //释放CS
            }
            rt_spi_transfer_message(spi_dev_w25q, &msg1);
            usb_putc(recv_buf[0] & 0xff);
            if (rlen < 10)
            {
                dbg("%2X ", recv_buf[0] & 0xff);
            }
        }
        dbg("\r\n");

    }
}
void serprog_handle_command(unsigned char command)
{

    static uint8_t i; /* Loop            */
    static uint8_t l; /* Length          */
    static uint32_t slen; /* SPIOP write len */
    static uint32_t rlen; /* SPIOP read len  */
    static uint32_t freq_req;
    switch (command)
    {
    case S_CMD_NOP:
        usb_putc(S_ACK);
        dbg("S_CMD_NOP\r\n");
        break;
    case S_CMD_Q_IFACE:
        dbg("S_CMD_Q_IFACE\r\n");
        usb_putc(S_ACK);
        /* little endian multibyte value to complete to 16bit */
        usb_putc(S_IFACE_VERSION);
        usb_putc(0);
        break;
    case S_CMD_Q_CMDMAP:
        dbg("S_CMD_Q_CMDMAP\r\n");
        usb_putc(S_ACK);
        /* little endian */
        usb_putu32(S_CMD_MAP);
        for (i = 0; i < 32 - sizeof(uint32_t); i++)
            usb_putc(0);
        break;
    case S_CMD_Q_PGMNAME:
        dbg("S_CMD_Q_PGMNAME\r\n");

        usb_putc(S_ACK);
        l = 0;
        while (S_PGM_NAME[l])
        {
            usb_putc(S_PGM_NAME[l]);
            l++;
        }
        for (i = l; i < 16; i++)
            usb_putc(0);
        break;
    case S_CMD_Q_SERBUF:
        dbg("S_CMD_Q_SERBUF\r\n");

        usb_putc(S_ACK);
        /* Pretend to be 64K (0xffff) */
        usb_putc(0xff);
        usb_putc(0xff);
        break;
    case S_CMD_Q_BUSTYPE:
        // TODO: LPC / FWH IO support via PP-Mode
        usb_putc(S_ACK);
        usb_putc(S_SUPPORTED_BUS);
        dbg("S_SUPPORTED_BUS\r\n");
        break;
    case S_CMD_Q_CHIPSIZE:
        break;
    case S_CMD_Q_OPBUF:
        // TODO: opbuf function 0
        break;
    case S_CMD_Q_WRNMAXLEN:
        break;
    case S_CMD_R_BYTE:
        break;
    case S_CMD_R_NBYTES:
        break;
    case S_CMD_O_INIT:
        dbg("S_CMD_O_INIT\r\n");
        break;
    case S_CMD_O_WRITEB:
        // TODO: opbuf function 1
        break;
    case S_CMD_O_WRITEN:
        // TODO: opbuf function 2
        break;
    case S_CMD_O_DELAY:
        // TODO: opbuf function 3
        break;
    case S_CMD_O_EXEC:
        // TODO: opbuf function 4
        break;
    case S_CMD_SYNCNOP:
        dbg("S_CMD_SYNCNOP\r\n");
        usb_putc(S_NAK);
        usb_putc(S_ACK);
        break;
    case S_CMD_Q_RDNMAXLEN:
        // TODO
        break;
    case S_CMD_S_BUSTYPE:
        dbg("S_CMD_S_BUSTYPE\r\n");

        /* We do not have multiplexed bus interfaces,
         * so simply ack on supported types, no setup needed. */
        if ((usb_getc() | S_SUPPORTED_BUS) == S_SUPPORTED_BUS)
            usb_putc(S_ACK);
        else
            usb_putc(S_NAK);
        break;
    case S_CMD_O_SPIOP:
        slen = usb_getu24();
        rlen = usb_getu24();
        dbg("S_CMD_O_SPIOP slen=%d rlen= %d\r\n", slen, rlen);
        // select_chip();

#if 1
        spi_tran(slen, rlen);
#else
        /* TODO: handle errors with S_NAK */
        if (slen)
        spi_bulk_write(slen);
        usb_putc(S_ACK);
        if (rlen)
        spi_bulk_read(rlen);

        // unselect_chip();
#endif

        break;
    case S_CMD_S_SPI_FREQ:

        freq_req = usb_getu32();
        if (freq_req == 0)
            usb_putc(S_NAK);
        else
        {
            usb_putc(S_ACK);
            usb_putu32((freq_req));
        }
        dbg("S_CMD_S_SPI_FREQ freq_req=%d r\n", freq_req);
        break;
    default:
        usb_putc('K');
        // usb_putc(KeyIn_power);
        break; // TODO: Debug malformed command
    }
    // LED0 ^= 1;
}

#endif

/* 接收数据回调函数 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    /* 串口接收到数据后产生中断，调用此回调函数，然后发送接收信号量 */
    rt_sem_release(&rx_sem);
    return RT_EOK;
}
static void serial_thread_entry(void *parameter)
{
    rt_err_t err;
    char ch;
    while (1)
    {
        // rt_thread_delay(5000 / RT_TICK_PER_SECOND / 1000);
#if 1
        serprog_handle_command(usb_getc());

#else
        /* 从串口读取一个字节的数据，没有读取到则等待接收信号量 */
        while (rt_device_read(serial, -1, &ch, 1) != 1)
        {
            /* 阻塞等待接收信号量，等到信号量后再次读取数据 */
            //rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
            err = rt_sem_take(&rx_sem, (5000 / 1));
            if (err == -RT_ETIMEOUT)
            {
                rt_kprintf("rt_sem_take(&rx_sem, (5000/RT_TICK_PER_SECOND/1000)) RT_ETIMEOUT \n");
            }
            else
            {
                rt_kprintf("uart1 recve 1 byte \n");
            }
        }
        /* 读取到的数据通过串口错位输出 */
        // ch = ch + 1;
        rt_device_write(serial, 0, &ch, 1);
#endif
    }
}
static int uart_sample(int argc, char *argv[])
{
    rt_err_t ret = RT_EOK;
    char uart_name[RT_NAME_MAX];
    char str[] = "hello RT-Thread!\r\n";
    if (argc == 2)
    {
        rt_strncpy(uart_name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);
    }
    /* 查找系统中的串口设备 */
    serial = rt_device_find(uart_name);
    if (!serial)
    {
        rt_kprintf("find %s failed!\n", uart_name);
        return RT_ERROR;
    }
    rt_kprintf("found %s  OK!\n", uart_name);

    /* 初始化信号量 */
    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
    /* 以中断接收及轮询发送模式打开串口设备 */
    rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
    /* 设置接收回调函数 */
    rt_device_set_rx_indicate(serial, uart_input);
    /* 发送字符串 */
    // rt_device_write(serial, 0, str, (sizeof(str) - 1));
    /* 创建 serial 线程 */
    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
    /* 创建成功则启动线程 */
    if (thread != RT_NULL)
    {
        rt_thread_startup(thread);
    }
    else
    {
        ret = RT_ERROR;
    }
    return ret;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(uart_sample, uart device sample);
INIT_ENV_EXPORT(uart_sample);

//由于在初始化串口时，默认波特率是 1500000，可以在 libraries->hal_drivers->drv_usart.c
//中 int rt_hw_usart_init(void)做些修改。
#if 0
int rt_hw_usart_init(void)
{
    rt_size_t obj_num = sizeof(uart_obj) / sizeof(struct ab32_uart);
    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
    rt_err_t result = 0;
    rt_hw_interrupt_install(IRQ_UART0_2_VECTOR, uart_isr, RT_NULL, "ut_isr");
    for (int i = 0; i < obj_num; i++)
    {
        /* init UART object */
        uart_obj[i].config = &uart_config[i];
        uart_obj[i].rx_idx = 0;
        uart_obj[i].rx_idx_prev = 0;
        uart_obj[i].serial.ops = &ab32_uart_ops;
        uart_obj[i].serial.config = config;
        uart_obj[i].serial.config.baud_rate = 1500000;
        uart_obj[i].rx_buf = rt_malloc(uart_config[i].fifo_size);
        if (uart_obj[i].rx_buf == RT_NULL)
        {
            LOG_E("uart%d malloc failed!", i);
            continue;
        }
//如果是串口 1，修改波特率位 115200
        if (i == 1)
        {
            uart_obj[i].serial.config.baud_rate = 115200;
        }
//------------------
        /* register UART device */
        result = rt_hw_serial_register(&uart_obj[i].serial, uart_obj[i].config->name,
                RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX | uart_obj[i].uart_dma_flag, NULL);
        RT_ASSERT(result == RT_EOK);
    }
    return result;
}
#endif

